/*
 * Copyright 2011 Jin Kwon <jinahya at gmail.com>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.googlecode.flac4j.format.metadata;


import com.googlecode.flac4j.format.Stream;

import com.googlecode.jinahya.io.BitInput;
import com.googlecode.jinahya.io.BitOutput;
import com.googlecode.jinahya.util.BitAccessible;

import java.io.IOException;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;


/**
 *
 * @author Jin Kwon <jinahya at gmail.com>
 */
@XmlType(propOrder = {"header", "data"})
public class Block implements BitAccessible {


    @Override
    public void read(final BitInput input) throws IOException {

        header = new Header();
        header.setBlock(this);
        header.read(input);

        switch (header.getBlockType()) {
            case STREAMINFO:
                data = new StreamInfo();
                break;
            case PADDING:
                data = new Padding();
                break;
            case APPLICATION:
                data = new Application();
                break;
            case SEEKTABLE:
                data = new Seektable();
                break;
            case VORBIS_COMMENT:
                data = new VorbisComment();
                break;
            case CUESHEET:
                data = new Cuesheet();
                break;
            case PICTURE:
                data = new Picture();
                break;
            default:
                throw new RuntimeException(
                    "uknown blockType: " + header.getBlockType());
        }

        data.setBlock(this);
        data.read(input);
    }


    @Override
    public void write(final BitOutput output) throws IOException {

        header.setBlockType(data.getBlockType());
        header.setDataLength(data.getLengthInBytes());

        header.write(output);
        data.write(output);
    }


    /**
     * Returns stream.
     *
     * @return stream
     */
    public final Stream getStream() {
        return stream;
    }


    /**
     * Sets stream.
     *
     * @param stream stream
     */
    public final void setStream(final Stream stream) {

        if (stream == null) {
            throw new NullPointerException("null stream");
        }

        this.stream = stream;
    }


    /**
     * Returns header.
     *
     * @return header
     */
    public final Header getHeader() {

        return header;
    }


    /**
     * Sets header.
     *
     * @param header header
     */
    public final void setHeader(final Header header) {

        if (header == null) {
            throw new NullPointerException("null header");
        }

        header.setBlock(this);
        if (data != null) {
            header.setDataLength(data.getLengthInBytes());
        }

        this.header = header;
    }


    /**
     * Returns data.
     *
     * @return data.
     */
    public final Data getData() {
        return data;
    }


    /**
     * Sets data.
     *
     * @param data data.
     */
    public final void setData(final Data data) {

        if (data == null) {
            throw new NullPointerException("null data");
        }

        data.setBlock(this);
        if (header != null) {
            header.setDataLength(data.getLengthInBytes());
        }

        this.data = data;
    }


    @XmlTransient
    private Stream stream;


    @XmlElement(required = true)
    private Header header;


    @XmlElement(required = true)
    private Data data;


}

